using System;
using System.Collections.Generic;
using System.IO;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
namespace Nyanimals
{
	public class CSkeletalMesh : CMesh
	{
		private int numBones;
		private List<tBone> boneList;
		private float[] jointIndices;
		private float[] weights;
		
		public List<tBone> Bones
		{
			get { return boneList;}
		}
		
		public CSkeletalMesh ()
		{
			loaded = false;
		}
        
        
        public override MeshTypes Type
        {
            get { return MeshTypes.Skeletal;} 
        }
        
		public override void Load(string szFileName, BinaryReader read)
		{
			// dont continue if we are already loaded
			if(loaded == true)
			{
				return;
			}
			
            name = new string(szFileName.ToCharArray());
            
			// read in the count of stuff
			numVerts = read.ReadInt32();
			numTris = read.ReadInt32();
			numIndices = numTris * 3;
						
			// read in all the texture names
			int numTextures = read.ReadInt32();		
			Textures = new List<int>(numTextures);
			
			for(int texCount = 0; texCount < numTextures; ++texCount)
			{
				int textureLength = read.ReadInt32();
				string textureName = new string(read.ReadChars(textureLength));
				
				// add the texture
				Textures.Add(CTextureManager.Instance.LoadTexture(textureName));
			}
					
			/* TODO: Support UV scrolling on skeletal meshes...
			// read in the UV scrolling data
			UV_X = read.ReadSingle();
			UV_Y = read.ReadSingle();		
			*/
			
			// build contiguous vert layouts
			pos = new float[numVerts * 3];
			norm = new float[numVerts * 3];
			tan = new float[numVerts * 3];
			UV = new float[numVerts * 2];
			indices = new ushort[numTris * 3];
			
			jointIndices = new float[numVerts * 2];
			weights = new float[numVerts * 2];
			
			// read in all the verts
			int vertPos = 0;
			int UVPos = 0;
			for(int vertCount = 0; vertCount < numVerts; ++vertCount)
			{
				pos[vertPos + 0] = read.ReadSingle();
				pos[vertPos + 1] = read.ReadSingle();
				pos[vertPos + 2] = -read.ReadSingle();
				
				norm[vertPos + 0] = read.ReadSingle();
				norm[vertPos + 1] = read.ReadSingle();
				norm[vertPos + 2] = -read.ReadSingle();
				
				tan[vertPos + 0] = read.ReadSingle();
				tan[vertPos + 1] = read.ReadSingle();
				tan[vertPos + 2] = -read.ReadSingle();
				
				UV[UVPos + 0] = read.ReadSingle();
				UV[UVPos + 1] = read.ReadSingle();
				
				// read in all the influences and weights
				// NOTE: the MAXINFLUENCE is 2
				int numInfluences = read.ReadInt32();
				
				jointIndices[UVPos + 0] = (float)read.ReadInt32();
				weights[UVPos + 0] = read.ReadSingle();
				
				if(numInfluences == 2)
				{
					jointIndices[UVPos + 1] = (float)read.ReadInt32();
					weights[UVPos + 1] = read.ReadSingle();
				}
				else
				{
					jointIndices[UVPos + 1] = 0;
					weights[UVPos + 0] = 1.0f;
					weights[UVPos + 1] = 0.0f;
				}
				
				vertPos += 3;
				UVPos += 2;
			}
		
				// read in the triangle data
			for(int indexCount = 0; indexCount < numIndices; indexCount += 3)
			{
				// load with reversed winding order
				indices[indexCount + 0] = (ushort)read.ReadInt32();
				indices[indexCount + 1] = (ushort)read.ReadInt32();
				indices[indexCount + 2] = (ushort)read.ReadInt32();
			}
			
			// read in the bones
			numBones = read.ReadInt32();
			boneList = new List<tBone>(numBones);
			
			for(int boneIndex = 0; boneIndex < numBones; ++boneIndex)
			{
				tBone bone = new tBone();
				
				// identification
				bone.MyIndex = read.ReadInt32();
				bone.ParentIndex = read.ReadInt32();
				
				int nameLength = read.ReadInt32();
				bone.Name = new string(read.ReadChars(nameLength));
				
				bone.LocalMatrix = new Matrix4(read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), 
				                               read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), 
				                               read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), 
				                               read.ReadSingle(), read.ReadSingle(), read.ReadSingle(), read.ReadSingle());
				
				Matrix4 scale = Matrix4.Scale(1.0f, 1.0f, -1.0f);
				bone.LocalMatrix = scale * bone.LocalMatrix;
				
				// kidnap the kiddies(from the file... x.x)
				int numKids = read.ReadInt32();
				bone.Node = new tSkeletonNode();
				bone.Node.JointIndex = bone.MyIndex;
				bone.Node.Children = new List<tSkeletonNode>(numKids);
				
				for(int kidIndex = 0; kidIndex < numKids; ++kidIndex)
				{
					tSkeletonNode newKid = new tSkeletonNode();
					newKid.JointIndex = read.ReadInt32();
					bone.Node.Children.Add(newKid);
				}			
				
				boneList.Add(bone);
			}	
			
			loaded = true;
			
	
			// TODID: push the weights and joint index
			// TODID: the joint index might need to be floats
			// TODO: And make the shader and the render func in the animated context
            VertexFormat[] vf = {VertexFormat.Float3, VertexFormat.Float2, VertexFormat.Float2, VertexFormat.Float2};
			vertexBuffer = new VertexBuffer(numVerts, numIndices, vf);
			vertexBuffer.SetVertices(0, pos);
			vertexBuffer.SetVertices(1, UV);
			vertexBuffer.SetVertices(2, jointIndices);
			vertexBuffer.SetVertices(3, weights);
			// vertexBuffer.SetVertices(1, norm);
			// vertexBuffer.SetVertices(2, tan);
			// vertexBuffer.SetVertices(3, UV);
			vertexBuffer.SetIndices(indices);
			
		}
	}
}

